﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

/// <summary>
/// ECS事件
/// </summary>
public class ECSEvent
{
    public delegate void ECSEventHandle(ECSEntityBase entity, params object[] objs);
    private ECSWorldBase m_world;
    /// <summary>
    /// ECS_Inter——PLay事件
    /// </summary>
    private Dictionary<string,ECSEventHandle> m_ECSEventDic=new Dictionary<string, ECSEventHandle>();
    /// <summary>
    /// ECS确定性事件字典（重计算和本地计算使用）
    /// </summary>
    private Dictionary<string,ECSEventHandle> m_CertaintyECSEventDic=new Dictionary<string, ECSEventHandle>();
    /// <summary>
    /// 派发过的事件缓存(本地运行或者确定性运行不加入此缓存)
    /// </summary>
    private List<MyEventCacheStruct> m_eventCache=new List<MyEventCacheStruct>();

    #region EventCache
    /// <summary>
    /// 事件缓存
    /// </summary>
    public struct MyEventCacheStruct
    {
        public int frame;//哪一帧
        public string eventKey;//键
        public ECSEntityBase entity;//对应实体
        public object[] objs;//参数
    }
    #endregion
    //构造
    public ECSEvent(ECSWorldBase world)
    {
        m_world = world;
    }

    public void AddListener(string key, ECSEventHandle handle, bool certainty = false)
    {
        if (!certainty)
        {
            if (m_ECSEventDic.ContainsKey(key))
            {
                m_ECSEventDic[key] += handle;
            }
            else
            {
                m_ECSEventDic.Add(key,handle);
            }
        }
        else
        {
            if (m_CertaintyECSEventDic.ContainsKey(key))
            {
                m_CertaintyECSEventDic[key] += handle;
            }
            else
            {
                m_CertaintyECSEventDic.Add(key, handle);
            }
        }
    }
    public void RemoveListener(string key, ECSEventHandle handle, bool certainty = false)
    {
        if (!certainty)
        {
            if (m_ECSEventDic.ContainsKey(key))
            {
                try
                {
                    m_ECSEventDic[key] -= handle;
                }
                catch (Exception e)
                {
                    Debug.LogError(e.ToString() + "移除ecs事件监听失败,key:" + key);
                }
            }
        }
        else
        {
            if (m_CertaintyECSEventDic.ContainsKey(key))
            {
                try
                {
                    m_CertaintyECSEventDic[key] -= handle;
                }
                catch (Exception e)
                {
                    Debug.LogError(e.ToString() + "移除ecs事件监听失败,key:" + key);
                }
            }
            
        }
    }
    /// <summary>
    /// 派发事件，如果非本地/确认。排发后加入事件派发缓存
    /// </summary>
    /// <param name="key"></param>
    /// <param name="entity"></param>
    /// <param name="objs"></param>
    public void DispatchListener(string key, ECSEntityBase entity, params object[] objs)
    {
        if (m_ECSEventDic.ContainsKey(key))
        {
            try
            {
                m_ECSEventDic[key](entity, objs);

            }
            catch (Exception e)
            {
                Debug.LogError("派发事件失败，key："+key+e.ToString());
            }
        }
        //如果本地运行或者确定

        if (m_world.IsCertainty ||m_world.IsLocal)
        {
            if (m_CertaintyECSEventDic.ContainsKey(key))
            {
                try
                {
                    m_CertaintyECSEventDic[key](entity, objs);
                }
                catch (Exception e)
                {
                    Debug.LogError("派发事件失败，key：" + key+ "m_world.IsCertainty||m_world.IsLocal"+e.ToString());
                }
            }
        }
        else//派发事件键入派发缓存m_eventCache
        {
            MyEventCacheStruct ca=new MyEventCacheStruct();
            ca.frame = m_world.FrameCount;
            ca.eventKey = key;
            ca.entity = entity;
            ca.objs = objs;
            //派发事件键入派发缓存m_eventCache
            m_eventCache.Add(ca);
        }

    }
    /// <summary>
    /// 派发第几帧之前的缓存中符合的事件(确定性事件派发)
    /// </summary>
    /// <param name="frame"></param>
    public void DispatchCertainty(int frame)
    {
        for (int i = 0,j=m_eventCache.Count; i < j; i++)
        {
            MyEventCacheStruct ca = m_eventCache[i];
            if (ca.frame<=frame)
            {
                if (m_CertaintyECSEventDic.ContainsKey(ca.eventKey))
                {
                    m_CertaintyECSEventDic[ca.eventKey](ca.entity, ca.objs);
                }
                m_eventCache.RemoveAt(i);
                i--;
                j--;
            }
           
        }
    }
    /// <summary>
    /// 清空已派发的事件缓存
    /// </summary>
    public void ClearCache()
    {
        m_eventCache.Clear();
    }
    //移除符合条件的已派发事件的缓存
    public void ClearCacheBefore(int frame)
    {
        ClearFrame(frame, thisEnum.Before);
    }
    public void ClearCacheAt(int frame)
    {
        ClearFrame(frame, thisEnum.At);
    }
    public void ClearCacheAfter(int frame)
    {
        ClearFrame(frame,thisEnum.After);
    }

    public void ClearFrame(int frame, thisEnum mEnum)
    {
        switch (mEnum)
        {
            case thisEnum.After:
                for (int i = 0,j= m_eventCache.Count; i <j; i++)//循环事件参数魂村列表
                {
                    MyEventCacheStruct e = m_eventCache[i];//取出事件缓存
                    if (e.frame > frame)
                    {
                        m_eventCache.RemoveAt(i);//移除
                        i--;
                        j--;
                    }
                }
                break;
            case thisEnum.At:
                for (int i = 0, j = m_eventCache.Count; i < j; i++)//循环事件参数魂村列表
                {
                    MyEventCacheStruct e = m_eventCache[i];//取出事件缓存
                    if (e.frame == frame)
                    {
                        m_eventCache.RemoveAt(i);//移除
                        i--;
                        j--;
                    }
                }
                break;
            case thisEnum.Before:
                for (int i = 0, j = m_eventCache.Count; i < j; i++)//循环事件参数魂村列表
                {
                    MyEventCacheStruct e = m_eventCache[i];//取出事件缓存
                    if (e.frame < frame)
                    {
                        m_eventCache.RemoveAt(i);//移除
                        i--;
                        j--;
                    }
                }
                break;
            default:
                Debug.LogError("标志位错误");
                break;
        }
    }
    public enum thisEnum
    {
        Before,
        At,
        After
    }
}

